#include "../StdInc.h"


#ifdef BUILD_WITH_BOOST

#include <boost/bind.hpp>
namespace GSTrader
{
	namespace Util
	{
		CAsyncTimer::CAsyncTimer(boost::asio::io_service& ios) : m_pIoservice(&ios)
		{
		}

		CAsyncTimer::~CAsyncTimer()
		{
			MapTimer::iterator it = m_mapTimer.begin();
			for (; it != m_mapTimer.end(); it++)
			{
				PTIMER_INFO pInfo = (PTIMER_INFO)(it->second);
				delete pInfo->timer;
				delete pInfo;
				pInfo = NULL;
			}
			m_mapTimer.clear();
			m_pIoservice->stop();
		}

		bool CAsyncTimer::KillTimer(int iTimerID)
		{
			MapTimer::iterator it = m_mapTimer.find(iTimerID);
			if (it == m_mapTimer.end())
			{
				return false;
			}

			PTIMER_INFO pInfo = (PTIMER_INFO)(it->second);
			pInfo->timer->cancel();
			m_mapTimer.erase(it);

			return true;
		}

		void CAsyncTimer::OnTimer(int iTimerID, const boost::system::error_code& error)
		{
			MapTimer::iterator it = m_mapTimer.find(iTimerID);
			if (it == m_mapTimer.end())
			{
				return;
			}

			PTIMER_INFO pInfo = (PTIMER_INFO)(it->second);

			pInfo->timer->expires_from_now(boost::posix_time::millisec(pInfo->iElapse));
			pInfo->timer->async_wait(boost::bind(&CAsyncTimer::OnTimerInternal, this, iTimerID, boost::asio::placeholders::error));
		}

		void CAsyncTimer::RunTimerThread(int iTimerID, int iElapse, void* pChild)
		{
			MapTimer::iterator it = m_mapTimer.find(iTimerID);
			if (it != m_mapTimer.end())
			{
				return ;
			}

			PTIMER_INFO pInfo = new TIMER_INFO;
			pInfo->iTimerID = iTimerID;
			pInfo->iElapse = iElapse;
			pInfo->pChild = pChild;

			pInfo->timer =  new boost::asio::deadline_timer(*m_pIoservice);
			pInfo->timer->expires_from_now(boost::posix_time::millisec(iElapse));
			pInfo->timer->async_wait(boost::bind(&CAsyncTimer::OnTimerInternal, this, iTimerID, boost::asio::placeholders::error));

			m_mapTimer.insert(std::pair<int, PTIMER_INFO>(iTimerID, pInfo));
			m_pIoservice->run();
		}

		bool CAsyncTimer::SetTimer(int iTimerID, int iElapse, void* pChild)
		{
			new thread(bind(&CAsyncTimer::RunTimerThread, this, iTimerID, iElapse, pChild));
			return true;
		}

		void CAsyncTimer::OnTimerInternal(int iTimerID, const boost::system::error_code& error)
		{
			MapTimer::iterator it = m_mapTimer.find(iTimerID);
			if (it == m_mapTimer.end())
			{
				return;
			}

			PTIMER_INFO pInfo = (PTIMER_INFO)(it->second);

			((CAsyncTimer*)(pInfo->pChild))->OnTimer(iTimerID, error);

			CAsyncTimer::OnTimer(iTimerID, error);
		}
	}
}

#endif